package com.mia.props.common;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.mia.craftstudio.CSModel;
import com.mia.craftstudio.libgdx.Vector3;
import com.mia.props.DecoModelMetadata;
import com.mia.props.Props;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.EntitySpider;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.DamageSource;
import net.minecraft.util.IIcon;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;

public class BlockProps extends BlockContainer {
   private static final Cache eggedEntities;

   public BlockProps() {
      super(Material.cloth);
      this.setHardness(0.25F);
   }

   public ItemStack getPickBlock(MovingObjectPosition target, World world, int x, int y, int z, EntityPlayer player) {
      ItemStack stack = super.getPickBlock(target, world, x, y, z, player);
      if (player.isSneaking()) {
         TileEntity tile = Props.getTileEntityPreferNotCreating(world, x, y, z);
         if (tile instanceof TileProps && ((TileProps)tile).onItemStackDropSaveNBT()) {
            NBTTagCompound tag = new NBTTagCompound();
            tile.writeToNBT(tag);
            stack.setTagInfo("savedProp", tag);
         }
      }

      return stack;
   }

   public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int x, int y, int z) {
      TileEntity tile = Props.getTileEntityPreferNotCreating(par1IBlockAccess, x, y, z);
      if (tile instanceof TileProps) {
         Vector3[] bounds = ((DecoModelMetadata)Props.modelData.get(((TileProps)tile).type)).wrapper.getExtend(((TileProps)tile).rotation);
         this.setBlockBounds(bounds[0].x, bounds[0].y, bounds[0].z, bounds[1].x, bounds[1].y, bounds[1].z);
      }

   }

   public void addCollisionBoxesToList(World world, int x, int y, int z, AxisAlignedBB mask, List list, Entity ent) {
      TileEntity tile = Props.getTileEntityPreferNotCreating(world, x, y, z);
      if (tile instanceof TileProps) {
         DecoModelMetadata data = (DecoModelMetadata)Props.modelData.get(((TileProps)tile).type);
         if (data.walkthrough) {
            return;
         }

         CSModel model = data.csmodel;
         Iterator var11 = model.getNodes().iterator();

         while(var11.hasNext()) {
            CSModel.ModelNode node = (CSModel.ModelNode)var11.next();
            if (!node.hasAttribute(CSModel.ModelNode.Attrb.PASSABLE) && !node.hasAttribute(CSModel.ModelNode.Attrb.PASSABLEPROPAGATES)) {
               Vector3[] extend = data.wrapper.nodeCache.get(node).getExtend(((TileProps)tile).rotation);
               AxisAlignedBB aabb = AxisAlignedBB.getBoundingBox((double)extend[0].x, (double)extend[0].y, (double)extend[0].z, (double)extend[1].x, (double)extend[1].y, (double)extend[1].z);
               AxisAlignedBB aabbTmp = aabb.getOffsetBoundingBox((double)x, (double)y, (double)z);
               if (mask.intersectsWith(aabbTmp)) {
                  list.add(aabbTmp);
               }
            }
         }
      } else {
         super.addCollisionBoxesToList(world, x, y, z, mask, list, ent);
      }

   }

   public MovingObjectPosition collisionRayTrace(World world, int x, int y, int z, Vec3 origin, Vec3 direction) {
      TileEntity tile = Props.getTileEntityPreferNotCreating(world, x, y, z);
      if (!(tile instanceof TileProps)) {
         return super.collisionRayTrace(world, x, y, z, origin, direction);
      } else {
         DecoModelMetadata data = (DecoModelMetadata)Props.modelData.get(((TileProps)tile).type);
         MovingObjectPosition closest = null;
         CSModel model = data.csmodel;
         Iterator var11 = model.getNodes().iterator();

         while(true) {
            while(true) {
               MovingObjectPosition mop;
               do {
                  if (!var11.hasNext()) {
                     if (closest != null) {
                        closest.blockX = x;
                        closest.blockY = y;
                        closest.blockZ = z;
                     }

                     return closest;
                  }

                  CSModel.ModelNode node = (CSModel.ModelNode)var11.next();
                  Vector3[] extend = data.wrapper.nodeCache.get(node).getExtend(((TileProps)tile).rotation);
                  AxisAlignedBB aabb = AxisAlignedBB.getBoundingBox((double)extend[0].x, (double)extend[0].y, (double)extend[0].z, (double)extend[1].x, (double)extend[1].y, (double)extend[1].z);
                  mop = aabb.getOffsetBoundingBox((double)x, (double)y, (double)z).calculateIntercept(origin, direction);
               } while(mop == null);

               if (closest != null && mop.hitVec.distanceTo(origin) < closest.hitVec.distanceTo(origin)) {
                  closest = mop;
               } else {
                  closest = mop;
               }
            }
         }
      }
   }

   public boolean isOpaqueCube() {
      return false;
   }

   public boolean renderAsNormalBlock() {
      return false;
   }

   public int getRenderType() {
      return -1;
   }

   public TileEntity createNewTileEntity(World var1, int var2) {
      return new TileProps();
   }

   public ArrayList getDrops(World world, int x, int y, int z, int metadata, int fortune) {
      ArrayList ret = new ArrayList();
      return ret;
   }

   @SideOnly(Side.CLIENT)
   public Item getItem(World par1World, int par2, int par3, int par4) {
      return Props.itemProps;
   }

   public int getLightValue(IBlockAccess world, int x, int y, int z) {
      TileEntity tile = Props.getTileEntityPreferNotCreating(world, x, y, z);
      return tile instanceof TileProps ? ((TileProps)tile).getLightValue(world, x, y, z) : 0;
   }

   public int getDamageValue(World world, int x, int y, int z) {
      TileEntity tile = Props.getTileEntityPreferNotCreating(world, x, y, z);
      return tile instanceof TileProps ? ((TileProps)tile).type : 0;
   }

   @SideOnly(Side.CLIENT)
   public void registerIcons(IIconRegister par1IconRegister) {
   }

   public void onBlockHarvested(World world, int x, int y, int z, int par5, EntityPlayer par6EntityPlayer) {
      NBTTagCompound savedNBT = null;
      TileEntity tile = Props.getTileEntityPreferNotCreating(world, x, y, z);
      if (tile instanceof TileProps) {
         if (((TileProps)tile).onItemStackDropSaveNBT()) {
            savedNBT = new NBTTagCompound();
            tile.writeToNBT(savedNBT);
         }

         ((TileProps)tile).onBlockHarvested(world, x, y, z, par5, par6EntityPlayer);
      }

      if (!par6EntityPlayer.capabilities.isCreativeMode) {
         ItemStack droppedItem = new ItemStack(Props.itemProps, 1, this.getDamageValue(world, x, y, z));
         if (savedNBT != null) {
            droppedItem.setTagInfo("savedProp", savedNBT);
         }

         this.dropBlockAsItem(world, x, y, z, droppedItem);
      }

   }

   @SideOnly(Side.CLIENT)
   public IIcon getIcon(int side, int meta) {
      return Blocks.soul_sand.getIcon(side, 0);
   }

   public void onBlockClicked(World world, int x, int y, int z, EntityPlayer player) {
      TileEntity tile = Props.getTileEntityPreferNotCreating(world, x, y, z);
      if (tile instanceof TileProps) {
         ((TileProps)tile).onBlockClicked(world, x, y, z, player);
      }

   }

   private void playBlockSound(World world, TileProps prop, Entity player) {
      if (!world.isRemote) {
         if (prop != null) {
            String sfx = ((DecoModelMetadata)Props.modelData.get(prop.type)).sound;
            if (sfx != null) {
               world.playSoundAtEntity(player, "props:" + sfx, 1.0F, 1.0F);
            }
         }

      }
   }

   public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float var7, float var8, float var9) {
      TileEntity tile = Props.getTileEntityPreferNotCreating(world, x, y, z);
      if (tile instanceof TileProps) {
         this.playBlockSound(world, (TileProps)tile, player);
         return ((TileProps)tile).onBlockActivated(world, x, y, z, player, side, var7, var8, var9);
      } else {
         return false;
      }
   }

   @SideOnly(Side.CLIENT)
   public void randomDisplayTick(World world, int x, int y, int z, Random random) {
      TileEntity tile = Props.getTileEntityPreferNotCreating(world, x, y, z);
      if (tile instanceof TileProps) {
         ((TileProps)tile).renderParticles(world, x, y, z, random);
      }

   }

   public boolean isBed(IBlockAccess world, int x, int y, int z, EntityLivingBase player) {
      TileEntity tile = Props.getTileEntityPreferNotCreating(world, x, y, z);
      return tile instanceof TileProps ? ((TileProps)tile).isBed() : false;
   }

   public int getBedDirection(IBlockAccess world, int x, int y, int z) {
      TileEntity tile = Props.getTileEntityPreferNotCreating(world, x, y, z);
      return tile instanceof TileProps && ((TileProps)tile).isBed() ? ((TileProps)tile).rotation / 4 : super.getBedDirection(world, x, y, z);
   }

   public boolean isBedFoot(IBlockAccess world, int x, int y, int z) {
      return super.isBedFoot(world, x, y, z);
   }

   public boolean removedByPlayer(World world, EntityPlayer player, int x, int y, int z, boolean willHarvest) {
      TileEntity master = Props.getTileEntityPreferNotCreating(world, x, y, z);
      if (master instanceof TileProps) {
         ((TileProps)master).removeSlaves();
      }

      world.setBlockToAir(x, y, z);
      return true;
   }

   private static void eggCacheAndSpawnEntity(Entity newSpawn, World world, double x, double y, double z) {
      newSpawn.setLocationAndAngles(x + (double)((world.rand.nextFloat() - 0.5F) / 4.0F), y + (double)((world.rand.nextFloat() - 0.5F) / 4.0F), z + (double)((world.rand.nextFloat() - 0.5F) / 4.0F), world.rand.nextFloat() * 360.0F, 0.0F);
      newSpawn.setInWeb();
      world.spawnEntityInWorld(newSpawn);
      eggedEntities.put(newSpawn, new BlockProps.TimedBool(false, System.currentTimeMillis()));
   }

   static void onEntityWebbed(Entity webbedEntity, World world) {
      webbedEntity.setInWeb();
      if (!world.isRemote && !webbedEntity.isDead) {
         BlockProps.TimedBool egged = (BlockProps.TimedBool)eggedEntities.getIfPresent(webbedEntity);
         if (egged == null || !egged.value && egged.time + 500L <= System.currentTimeMillis()) {
            if (egged == null) {
               egged = new BlockProps.TimedBool(true, System.currentTimeMillis());
            }

            egged.value = true;
            eggedEntities.put(webbedEntity, egged);
            if (webbedEntity instanceof EntitySpider) {
               if ((double)world.rand.nextFloat() <= 0.3D) {
                  Constructor[] ctors = webbedEntity.getClass().getDeclaredConstructors();
                  Constructor ctor = null;

                  for(int i = 0; i < ctors.length; ++i) {
                     if (ctors[i].getParameterTypes().length == 1 && ctors[i].getParameterTypes()[0].isAssignableFrom(World.class)) {
                        ctor = ctors[i];
                        break;
                     }
                  }

                  if (ctor != null) {
                     try {
                        eggCacheAndSpawnEntity((Entity)ctor.newInstance(world), world, webbedEntity.posX, webbedEntity.posY, webbedEntity.posZ);
                     } catch (InstantiationException var6) {
                     } catch (IllegalAccessException var7) {
                     } catch (IllegalArgumentException var8) {
                     } catch (InvocationTargetException var9) {
                     }
                  }
               }
            } else if (webbedEntity instanceof EntityPlayer && (double)world.rand.nextFloat() <= 0.5D) {
               eggCacheAndSpawnEntity(new EntitySpider(world), world, webbedEntity.posX, webbedEntity.posY, webbedEntity.posZ);
            }
         }

      }
   }

   public void onEntityCollidedWithBlock(World world, int x, int y, int z, Entity collidingEntity) {
      TileEntity tile = Props.getTileEntityPreferNotCreating(world, x, y, z);
      if (tile instanceof TileProps) {
         if (((TileProps)tile).getModelData().spiderweb) {
            onEntityWebbed(collidingEntity, world);
         }
      }

   }

   static {
      eggedEntities = CacheBuilder.newBuilder().weakKeys().expireAfterAccess(2500L, TimeUnit.MILLISECONDS).build();
   }

   private static class TimedBool {
      public boolean value;
      public long time;

      public TimedBool(boolean v, long t) {
         this.value = v;
         this.time = t;
      }
   }
}
